package com.alibaba.cirtus.ots.application.adapter.ability.facade.serviceV2.sap;

import com.alibaba.cirtus.ots.application.adapter.ability.model.request.ModifyOrderLineRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.model.request.ModifyOrderRequest;
import com.alibaba.cirtus.ots.application.adapter.ability.model.response.ScItemFromDBResponse;
import com.alibaba.cirtus.ots.application.adapter.ability.model.response.ScItemResult;
import com.alibaba.cirtus.ots.application.adapter.ability.model.response.ScItemSearchResult;
import com.alibaba.cirtus.ots.application.adapter.ability.utils.CodeUtil;
import com.alibaba.cirtus.ots.application.adapter.ability.utils.ResponseUtil;
import com.alibaba.citrus.cr.common.enums.ordercenter.AsyncMessageEventEnum;
import com.alibaba.citrus.cr.common.enums.ordercenter.SalesOrderPushStatusEnum;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.util.IntegrateUtils;
import com.alibaba.citrus.ots.common.util.JsonUtil;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.citrus.ots.common.util.TimeUtil;
import com.alibaba.cz.base.tool.Nullable;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.middleware.mq.runtime.EpochMessageService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.*;
import com.epoch.app.bcorder.service.BaseDataService;
import com.epoch.app.bcorder.service.UnifiedInventoryService;
import com.epoch.app.bcots.contants.BcOtsConstants;
import com.epoch.app.crb2btradecenter.api.orderquery.dto.QuerySingleRequest;
import com.epoch.app.crb2btradecenter.api.orderquery.service.OrderQueryService;
import com.epoch.app.crb2btradecenter.api.orderwrite.service.OrderWriteService;
import com.epoch.app.crb2btradecenter.domain.order.dto.LoadOrderListRequest;
import com.epoch.app.crb2btradecenter.domain.order.dto.LoadOrderRequest;
import com.epoch.app.crb2btradecenter.domain.order.model.Order;
import com.epoch.app.crb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.crb2btradecenter.model.dto.OrderBackUpLoadListRequest;
import com.epoch.app.crb2btradecenter.orderbackup.model.OrderBackUp;
import com.epoch.app.crb2btradecenter.orderbackup.service.OrderBackUpService;
import com.epoch.app.crb2btradecenter.sdo.OrderSDO;
import com.epoch.app.crforecastsales.api.forecastorderlinequery.service.ForecastOrderLineQueryService;
import com.epoch.app.crforecastsales.model.dto.ActivitySDO;
import com.epoch.app.crforecastsales.model.dto.QuerySaleUnitRequest;
import com.epoch.app.crforecastsales.model.dto.SelectCombox;
import com.epoch.app.crplatformenhance.api.group.scitemgroupquery.service.ScItemGroupQueryService;
import com.epoch.app.crplatformenhance.api.organizationquery.service.OrganizationQueryService;
import com.epoch.app.crplatformenhance.domain.customer.dto.CustomerLoadListRequest;
import com.epoch.app.crplatformenhance.domain.customer.model.Customer;
import com.epoch.app.crplatformenhance.domain.customer.service.CustomerService;
import com.epoch.app.crplatformenhance.domain.customeraddress.dto.CustomerAddressLoadListRequest;
import com.epoch.app.crplatformenhance.domain.customeraddress.model.CustomerAddress;
import com.epoch.app.crplatformenhance.domain.customeraddress.service.CustomerAddressService;
import com.epoch.app.crplatformenhance.dto.request.IdQueryRequest;
import com.epoch.app.crplatformenhance.dto.request.QueryScItemGroupRequest;
import com.epoch.app.crplatformenhance.dto.response.ScItemGroupResponse;
import com.epoch.app.crplatformenhance.interfacedatasyncconfigquery.service.InterfaceDataSyncConfigQueryService;
import com.epoch.app.crplatformenhance.model.dto.DataCheckRequest;
import com.epoch.app.crplatformenhance.model.dto.OrderCheckSalePrincipalRequest;
import com.epoch.app.crplatformenhance.model.dto.OrderCheckSalePrincipalResponse;
import com.epoch.app.crplatformenhance.model.enums.OrderTypeEnum;
import com.epoch.app.crplatformenhance.sdo.CustomerAddressSDO;
import com.epoch.app.crplatformenhance.service.CrPlatformEnhanceService;
import com.epoch.app.crpricecenter.api.creditquery.service.CreditQueryService;
import com.epoch.app.crpricecenter.model.dto.CreditInfoSDO;
import com.epoch.app.crpricecenter.model.dto.CreditQueryRequest;
import com.epoch.app.mnordercenter.model.dto.CommonAsyncMessageResponse;
import com.epoch.app.mnordercenter.model.dto.PushOrderInfoToMnSideRequestOrderInfo;
import com.epoch.app.otsapplicationadaptersdk.contants.OtsApplicationAdapterSdkConstants;
import com.epoch.app.otsapplicationadaptersdk.materialsyncretry.model.MaterialSyncRetry;
import com.epoch.app.otsapplicationadaptersdk.materialsyncretry.service.MaterialSyncRetryService;
import com.epoch.app.otsapplicationadaptersdk.model.dto.*;
import com.epoch.app.otsapplicationadaptersdk.model.enums.RetryStatus;
import com.epoch.app.otsapplicationadaptersdk.model.enums.SapApiCode;
import com.epoch.app.otsapplicationadaptersdk.sap.*;
import com.epoch.app.otsapplicationadaptersdk.sapretry.dto.LoadRequest;
import com.epoch.app.otsapplicationadaptersdk.sapretry.model.SapRetry;
import com.epoch.app.otsapplicationadaptersdk.sapretry.service.SapRetryService;
import com.epoch.app.otsapplicationadaptersdk.sapretrywrite.service.SapRetryWriteService;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mnsapif004v2.service.MnSapIf004V2Service;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mnsapif015v2.service.MnSapIf015V2Service;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mnsapif017v2.service.MnSapIf017V2Service;
import com.epoch.app.otsapplicationadaptersdk.service.BcService;
import com.epoch.app.otsapplicationadaptersdk.service.OtsApplicationAdapterSdkService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author
 * @date 2021/10/12
 * @Description sap请求平台销售单分公司更改
 * SAP将B-b销售订单明细回传中台（创建、更改）
 */
@Component
@Primary
public class MnSapIf015V2ServiceImpl implements MnSapIf015V2Service {
    private final Log log = Log.getLogger(MnSapIf015V2ServiceImpl.class);

    @Autowired
    private BaseDataService baseDataService;
    @Autowired
    private ScItemGroupQueryService scItemGroupQueryService;
    @Autowired
    private UnifiedInventoryService unifiedInventoryService;
    @Autowired
    private ForecastOrderLineQueryService forecastOrderLineQueryService;
    @Autowired
    private CreditQueryService creditQueryService;
    @Autowired
    private CrPlatformEnhanceService crPlatformEnhanceService;
    @Autowired
    private InterfaceDataSyncConfigQueryService interfaceDataSyncConfigQueryService;
    @Autowired
    private OrganizationQueryService organizationQueryService;
    @Resource
    private OrderWriteService orderWriteService;
    @Resource
    private OrderQueryService orderQueryService;
    @Resource
    private SapRetryWriteService sapRetryWriteService;
    @Resource
    private EpochCacheService epochCacheService;
    @Resource
    private SapRetryService sapRetryService;
    @Resource
    private OrderService orderService;
    @Resource
    private MaterialSyncRetryService materialSyncRetryService;
    @Resource(type = MnSapIf004V2ServiceImpl.class)
    private MnSapIf004V2Service mnSapIf004V2Service;
    @Resource(type = MnSapIf017V2ServiceImpl.class)
    private MnSapIf017V2Service mnSapIf017V2Service;
    @Resource
    private OrderBackUpService orderBackUpService;
    @Resource
    private EpochMessageService messageService;
    @Resource
    private CustomerAddressService customerAddressService;
    @Resource
    private CustomerService customerService;
    private static final Integer MAX_PAGE_SIZE = 1000;
    private static final String SALES_ORDER_CACHE_KEY = "SALES_ORDER_CACHE_KEY_";
    private static final Long SAP_TIMESTAMP_CACHE_EXPIRE = 60 * 60 * 24 * 100L;
    @Value("${ots.checkTimestamp:0}")
    private boolean checkTimestamp;
    @Resource
    private BcService bcService;
    @Resource
    private OtsApplicationAdapterSdkService otsApplicationAdapterSdkService;

    @Override
    @ProcessInvoker(remark = "MnSapIf015V2Service", errorCode = "OTS-02-007-00-16-999", printLog = true)
    public MnSapCommResponse externalSyncSaleOrder(MnSapIf015Request mnSapIf015Request) {
        log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder mnSapIf015Request={}", JSONObject.toJSONString(mnSapIf015Request));
        MnSapCommResponse response = new MnSapCommResponse();
        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
        try {
            mnSapCommSDO.setStatus("S");
            mnSapCommSDO.setMessage("成功");
            mnSapCommSDO.setHeaderKey(mnSapIf015Request.getData().getHeaderKey());
            // 2022.10.24 这个字段保持不变
            mnSapCommSDO.setExtId(mnSapIf015Request.getData().getTradeOrderId());
            //2022.10.19 sap报文里的订单id转换成内部主键id  sap: 1开头 中间补0  总长度10
            mnSapIf015Request.getData().setTradeOrderId(CodeUtil.convertTradeOrderId(mnSapIf015Request.getData().getTradeOrderId()));
            response.setInterfacePath(mnSapIf015Request.getMessageHeader().getInterfacePath());
            response.setMessageId(mnSapIf015Request.getMessageHeader().getMessageId());

            MnSapIf015SDO data = mnSapIf015Request.getData();
            // Try to get from mogodb if null
            if (data == null) {
                data = IntegrateUtils.safeGetMessageData(MnSapIf015SDO.class);
            }

            if (checkTimestamp) {
                // 校验时间戳格式
                String msg = ResponseUtil.check(data.getExt1());
                if (StringUtils.isNotBlank(msg)) {
                    List<MnSapCommDetail> mnSapCommDetails = null;
                    if (CollectionUtils.isNotEmpty(data.getItems())) {
                        mnSapCommDetails = new ArrayList<>();
                        for (MnSapIf015Detail item : data.getItems()) {
                            MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                            mnSapCommDetail.setItemKey(item.getItem_key());
                            mnSapCommDetail.setStatus("E");
                            mnSapCommDetail.setMessage(msg);
                            mnSapCommDetails.add(mnSapCommDetail);
                        }
                    }
                    buildFailResponse(mnSapCommSDO, msg, null, mnSapCommDetails);
                    response.setData(Lists.newArrayList(mnSapCommSDO));
                    log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                    return response;
                }

                // 判断时间戳，过滤老的请求
                if (!checkModifierTime(data, mnSapCommSDO, mnSapIf015Request)) {
                    response.setData(Lists.newArrayList(mnSapCommSDO));
                    log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                    return response;
                }
            }

            // 查询订单备份表是否存在，存在则表示订单已经删除，阻断流程
            OrderBackUpLoadListRequest orderBackUpLoadListRequest = new OrderBackUpLoadListRequest();
            orderBackUpLoadListRequest.setOuterOrderId(SapAndCrmFieldDealUtils.generateIdField(data.getOutOrderId()));
            Result<List<OrderBackUp>> backUpResult = orderBackUpService.loadList(orderBackUpLoadListRequest);
            if (backUpResult != null && CollectionUtils.isNotEmpty(backUpResult.getResult())) {
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder order_is_deleted");
                response.setData(Lists.newArrayList(mnSapCommSDO));
                return response;
            }

            // 查询订单信息，根据订单标来区分订单来源
            LoadOrderListRequest pageQueryRequest = new LoadOrderListRequest();
            pageQueryRequest.setOuterOrderId(data.getOutOrderId());
            Result<List<Order>> loadOrderListResult = orderService.loadOrderList(pageQueryRequest);
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder loadOrderList.result={}",
                    JSON.toJSONString(loadOrderListResult));

            Order order = null;
            if (Objects.isNull(loadOrderListResult) || CollectionUtils.isEmpty(loadOrderListResult.getResult())) {
                if (StringUtils.isNotBlank(data.getTradeOrderId())) {
                    LoadOrderRequest pageQueryRequest2 = new LoadOrderRequest();
                    pageQueryRequest2.setId(data.getTradeOrderId());
                    order = orderService.loadOrder(pageQueryRequest2);
                }
            } else {
                order = loadOrderListResult.getResult().get(0);
            }
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder order={}", JSON.toJSONString(order));

            // 识别是否是订单中心创建到订单，订单中心的订单要走业中的接口查询数据
            boolean isOrderCenterOrder = false;
            if (Objects.nonNull(order)) {
                isOrderCenterOrder = JsonUtil.checkOrderCenterTag(order.getFeatures());
            }
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder isOrderCenterOrder={}", isOrderCenterOrder);
            boolean callCenterAPI = isOrderCenterOrder && checkSaleOrganizationCode(data.getSaleOrganizationCode());

            // 构建创建/更新订单入参
            ModifyOrderRequest request = new ModifyOrderRequest();
            request.setCreator(data.getCreator());
            request.setModifier(data.getModifier());
            request.setCreateDate(SapAndCrmFieldDealUtils.toDateString(data.getCreateDate()));
            request.setCreateTime(SapAndCrmFieldDealUtils.toDateString(data.getCreateTime()));
            request.setGmtModified(SapAndCrmFieldDealUtils.toDateString(data.getGmtModified()));
            request.setBeginTime(SapAndCrmFieldDealUtils.toDateString(data.getBeginTime()));

            request.setExpectedDeliveryTime(SapAndCrmFieldDealUtils.toDate(data.getExpectedDeliveryTime()));
            request.setShipType(data.getShipType());
            request.setRemark(data.getRemark());
            request.setCustomerReferenceNo(data.getCustomerReferenceNo());
            request.setCashCustomerName(data.getCashCustomerName());
            request.setCostCenter(data.getCostCenter());
            request.setCreateReason(data.getCreateReason());
            request.setPriceTime(SapAndCrmFieldDealUtils.toDateString(data.getPriceTime()));
            request.setFeatures(data.getFeatures());
            if(Objects.isNull(order)){
                request.setAutoFulfillment(data.getAutoFulfillment());
                request.setFulfillmentPriority(data.getFulfillmentPriority());
                request.setFulfillmentTypeCode(data.getFulfillmentTypeCode());
                request.setBisUnitOutCode(data.getBisUnitOutCode());
                request.setOrderChannelCode(data.getOrderChannelCode());
                request.setChannelOutCode(data.getChannelOutCode());
            }
            // 1. 根据配置表进行数据拦截过滤
            DataCheckRequest dataCheckRequest = new DataCheckRequest();
            dataCheckRequest.setOrderType(OrderTypeEnum.SALEORDER.getCode());
            dataCheckRequest.setChannelOutCode(data.getSapChannel());
            dataCheckRequest.setOrgOutCode(data.getSaleOrganizationCode());
            dataCheckRequest.setVariable(SapAndCrmFieldDealUtils.toDateString(data.getCreateDate()));
            Result<Boolean> dataCheckResult = interfaceDataSyncConfigQueryService.dataCheck(dataCheckRequest);
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder dataCheckResult={}", JSON.toJSONString(dataCheckResult));
            if (dataCheckResult != null && dataCheckResult.getResult() != null && !dataCheckResult.getResult()) {
                response.setData(Lists.newArrayList(mnSapCommSDO));
                return response;
            }
            request.setTradeOrderId(data.getTradeOrderId());
            request.setOutOrderId(SapAndCrmFieldDealUtils.generateIdField(data.getOutOrderId()));
            request.setOrderType(data.getOrderType());
            request.setCreditCheckStatus(data.getExt());

            // 2. 根据sap销售组织编码查询平台销售组织
            if (callCenterAPI) {
                // 订单中心的订单逻辑，走客户中心接口查询组织信息
                List<ActualSalesOrgListResp> salesOrgList = this.salesOrgPage(data);
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder salesOrgList={}", JSON.toJSONString(salesOrgList));
                if (CollectionUtils.isEmpty(salesOrgList)) {
                    String msg = "销售组织转换失败";
                    buildFailResponse(mnSapCommSDO, msg, "OTS-05-001-10-16-049", null);
                    response.setData(Lists.newArrayList(mnSapCommSDO));
                    log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                    saveSapRetry(mnSapIf015Request, msg);
                    return response;
                }
                request.setSaleOrganizationCode(salesOrgList.get(0).getId().toString());
//                request.setSaleOrganizationName(salesOrgList.get(0).getSalesOrgName());
            } else {
                // 订单共享的订单逻辑
                BaselineGetOrganizationByOutCodes2Request byOutCodes2Request = new BaselineGetOrganizationByOutCodes2Request();
                byOutCodes2Request.setOutCodes(Lists.newArrayList(data.getSaleOrganizationCode()));
                byOutCodes2Request.setStatus(1);
                BaselineGetOrganizationByOutCodes2Response byOutCodes2Response = baseDataService.baselineGetOrganizationByOutCodes2(byOutCodes2Request);
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder byOutCodes2Response={}", JSON.toJSONString(byOutCodes2Response));
                Map<String, OrganizationSDO> organizationSDOMap = new HashMap<>();
                if (Objects.nonNull(byOutCodes2Response) && CollectionUtils.isNotEmpty(byOutCodes2Response.getResult())) {
                    organizationSDOMap = byOutCodes2Response.getResult().stream()
                            .collect(Collectors.toMap(OrganizationSDO::getOutCode, org -> org, (k1, k2) -> k2));
                }
                if (!organizationSDOMap.containsKey(data.getSaleOrganizationCode())) {
                    String msg = "销售组织转换失败";
                    buildFailResponse(mnSapCommSDO, msg, "OTS-05-001-10-16-049", null);
                    response.setData(Lists.newArrayList(mnSapCommSDO));
                    log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                    saveSapRetry(mnSapIf015Request, msg);
                    return response;
                }
                request.setSaleOrganizationCode(organizationSDOMap.get(data.getSaleOrganizationCode()).getId());
                request.setSaleOrganizationName(organizationSDOMap.get(data.getSaleOrganizationCode()).getName());
            }

            // 3. 根据sap业务渠道编码查询平台业务渠道
            BaselineQueryChannelByPageRequest channelByPageRequest = new BaselineQueryChannelByPageRequest();
            channelByPageRequest.setOutCode(data.getSapChannel());
            Map map = (Map) baseDataService.baselineQueryChannelByPage(channelByPageRequest);
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder channelMap={}", JSON.toJSONString(map));
            JSONObject jsonMap = JSONObject.parseObject(JSONObject.toJSONString(map));
            JSONArray jsonArray = jsonMap.getJSONObject("result").getJSONArray("content");
            if (CollectionUtils.isEmpty(jsonArray)) {
                String msg = "业务渠道转换失败";
                buildFailResponse(mnSapCommSDO, msg, null, null);
                response.setData(Lists.newArrayList(mnSapCommSDO));
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                saveSapRetry(mnSapIf015Request, msg);
                return response;
            }
            JSONObject jsonObject1 = jsonArray.getJSONObject(0);
            request.setSapChannel(jsonObject1.getString("channelCode"));
            request.setSapChannelName(jsonObject1.getString("channelName"));

            // 4. 根据sap货品组编码查询平台货品组
            QueryScItemGroupRequest scItemGroupRequest = new QueryScItemGroupRequest();
            scItemGroupRequest.setCode(data.getProductGroupCode());
            Result<ScItemGroupResponse> scItemGroup = scItemGroupQueryService.getScItemGroup(scItemGroupRequest);
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder scItemGroup={}", JSON.toJSONString(scItemGroup));
            if (scItemGroup.getResult() == null) {
                String msg = "货品组编码转换失败";
                buildFailResponse(mnSapCommSDO, msg, null, null);
                response.setData(Lists.newArrayList(mnSapCommSDO));
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                saveSapRetry(mnSapIf015Request, msg);
                return response;
            }
            request.setProductGroupCode(scItemGroup.getResult().getCode());
            request.setProductGroupName(scItemGroup.getResult().getName());

            // 5. sap客户编码、客户收货地址编码->平台客户编码、客户收货地址编码
            CustomerAddressSDO customerAddressSDO;
            if (callCenterAPI) {
                // 订单中心的订单逻辑，走客户中心接口查询客户信息
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder queryShipToPartyAndSoldToParty data = {}",JSON.toJSONString(data));
                customerAddressSDO = queryShipToPartyAndSoldToParty(data);
            } else {
                // 订单共享的订单逻辑
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder pageQueryCustomerAddress data = {}",JSON.toJSONString(data));
                customerAddressSDO = pageQueryCustomerAddress(data.getDeliveryPartCode(),
                        data.getSoldPartCode(),
                        request.getSaleOrganizationCode(),
                        request.getSapChannel(),
                        request.getProductGroupCode());
            }
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder customerAddressSDO={}", JSON.toJSONString(customerAddressSDO));
            if (Objects.isNull(customerAddressSDO)) {
                String msg = "客户编码、收货地址转换失败";
                buildFailResponse(mnSapCommSDO, msg, null, null);
                response.setData(Lists.newArrayList(mnSapCommSDO));
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                saveSapRetry(mnSapIf015Request, msg);
                return response;
            }

            // 从013过来的请求，都是一盘货的订单，不是订单共享
            boolean from013 = "SI_ECC_SaleOrder_Update_Asyn_Out".equals(mnSapIf015Request.getMessageHeader().getInterfacePath());
            if (isOrderCenterOrder || from013) {
                // 订单中心的订单逻辑
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 订单中心的订单不校验销售负责人");
            } else {
                // 订单共享的订单逻辑
                // 根据销售组织编码查询是否需要校验销售负责人
                OrderCheckSalePrincipalRequest orderCheckSalePrincipalRequest = new OrderCheckSalePrincipalRequest();
                orderCheckSalePrincipalRequest.setSaleOrganizationCode(data.getSaleOrganizationCode());
                OrderCheckSalePrincipalResponse orderCheckSalePrincipalResponse = crPlatformEnhanceService.orderCheckSalePrincipal(orderCheckSalePrincipalRequest);
                Boolean checkPrincipal = Objects.nonNull(orderCheckSalePrincipalResponse) ? orderCheckSalePrincipalResponse.getResult() : Boolean.TRUE;
                if (checkPrincipal && StringUtils.isBlank(customerAddressSDO.getPrincipal())) {
                    String msg = "客户送达方没有分派销售负责人";
                    buildFailResponse(mnSapCommSDO, msg, null, null);
                    response.setData(Lists.newArrayList(mnSapCommSDO));
                    log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                    saveSapRetry(mnSapIf015Request, msg);
                    return response;
                }
            }

            request.setSoldPartCode(customerAddressSDO.getCustomerCode());
            request.setSoldPartName(customerAddressSDO.getCustomerName());
            request.setDeliveryPartCode(customerAddressSDO.getAddressCode());
            request.setDeliveryPartName(customerAddressSDO.getAddressName());
            request.setContactor(customerAddressSDO.getContactName());
            request.setContactorPhone(customerAddressSDO.getCellphoneNumber());
            //订单中心创建的订单，不修改销售部门和销售渠道
            if(!isOrderCenterOrder){
                request.setSaleDepartmentCode(customerAddressSDO.getOrgSaleDepartmentCode());
                request.setSaleDepartmentName(customerAddressSDO.getOrgSalesDepartmentName());
                request.setSaleChannelCode(customerAddressSDO.getOrgSaleChannelCode());
                request.setSaleChannelName(customerAddressSDO.getOrgSalesChannelName());
            }
            //request.setBisUnitCode(customerAddressSDO.getOrgBussinessUnitCode());



            // 6. 根据销售部门code查询销售部门名称
            if (StringUtils.isEmpty(customerAddressSDO.getOrgSaleDepartmentCode())) {
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 客户送达方未关联销售部门信息");
            } else {
                IdQueryRequest idQueryRequest = new IdQueryRequest();
                idQueryRequest.setId(customerAddressSDO.getOrgSaleDepartmentCode());
                Result<com.epoch.app.crplatformenhance.sdo.OrganizationSDO> orgResult = organizationQueryService.getOrganizationDetail(idQueryRequest);
                if (orgResult != null && orgResult.getResult() != null) {
                    request.setSaleDepartmentName(orgResult.getResult().getName());
                } else {
                    log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 未查询到销售部门 orgResult={}", JSON.toJSONString(orgResult));
                }
            }

            // 7. 根据销售渠道code查询销售渠道名称
            if (StringUtils.isEmpty(customerAddressSDO.getOrgSaleChannelCode())) {
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 客户送达方未关联销售渠道信息");
            } else {
                IdQueryRequest idQueryRequest = new IdQueryRequest();
                idQueryRequest.setId(customerAddressSDO.getOrgSaleChannelCode());
                Result<com.epoch.app.crplatformenhance.sdo.OrganizationSDO> orgResult = organizationQueryService.getOrganizationDetail(idQueryRequest);
                if (orgResult != null && orgResult.getResult() != null) {
                    //订单中心创建的订单，不修改销售部门和销售渠道
                    if(!isOrderCenterOrder) {
                        request.setSaleChannelName(orgResult.getResult().getName());
                    }
                } else {
                    log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 未查询到销售渠道 orgResult={}", JSON.toJSONString(orgResult));
                }
            }

            if (CollectionUtils.isNotEmpty(data.getItems())) {
                List<MnSapCommDetail> mnSapCommDetails = new ArrayList<>();
                List<ModifyOrderLineRequest> orderLineRequests = new ArrayList<>();
                List<String> outIdList = data.getItems().stream()
                        .map(mnSapIf015Detail -> SapAndCrmFieldDealUtils.generateScItemIdField(mnSapIf015Detail.getScItemId()))
                        .distinct().collect(Collectors.toList());
                // 8. 根据货品编码查询货品信息
                BaselineQueryScItemByPageFromDbRequest dbRequest = new BaselineQueryScItemByPageFromDbRequest();
                dbRequest.setOutIdList(outIdList);
                dbRequest.setStatusList(Lists.newArrayList("1", "-1"));
                dbRequest.setLimit(outIdList.size());
                log.info("baselineQueryScItemByPageFromDb param:{}", JSON.toJSONString(dbRequest));
                Object pageFromDb = baseDataService.baselineQueryScItemByPageFromDb(dbRequest);
                log.info("baselineQueryScItemByPageFromDb result:{}", JSON.toJSONString(pageFromDb));
                Result<List<ScItemSDO>> scItemSDOResult = convertSapRetryRetryResponse(pageFromDb);
                Map<String, ScItemSDO> scItemSDOMap = Maps.newHashMap();
                if (scItemSDOResult != null && CollectionUtils.isNotEmpty(scItemSDOResult.getResult())) {
                    scItemSDOResult.getResult().forEach(scItemSDO -> {
                        scItemSDOMap.put(scItemSDO.getOuterId(), scItemSDO);
                    });
                }
                String warehouseCode = null;
                for (MnSapIf015Detail detail : data.getItems()) {
                    MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                    mnSapCommDetail.setItemKey(detail.getItem_key());

                    ModifyOrderLineRequest lineRequest = new ModifyOrderLineRequest();
                    lineRequest.setOrderLineId(SapAndCrmFieldDealUtils.generateIdField(detail.getOrderLineId()));
                    lineRequest.setOutOrderLineId(SapAndCrmFieldDealUtils.generateIdField(detail.getOutOrderLineId()));
                    lineRequest.setSubTotalAmount(detail.getSubTotalAmount());
                    List<String> list = new ArrayList<>();
                    String scItemIdField = SapAndCrmFieldDealUtils.generateScItemIdField(detail.getScItemId());
                    list.add(scItemIdField);

                    if (scItemSDOMap.containsKey(scItemIdField)) {
                        ScItemSDO scItemSDO = scItemSDOMap.get(scItemIdField);
                        lineRequest.setProductBarCode(scItemSDO.getBarCode());
                        lineRequest.setScItemOutCode(scItemSDO.getOuterId());
                        lineRequest.setScItemName(scItemSDO.getTitle());
                        lineRequest.setScItemId(scItemSDO.getScItemId());
                        Map<String, String> features = scItemSDO.getFeatures();
                        if (MapUtils.isNotEmpty(features)) {
                            String unitName = features.get("unit");
                            String unitCode = features.get("unitName");
                            lineRequest.setCategoryCode(features.get("category"));
                            lineRequest.setCategoryDesc(features.get("categoryDesc"));
                            lineRequest.setCategoryChildCode(features.get("categoryChildCode"));
                            lineRequest.setCategoryChildDesc(features.get("categoryChildDesc"));
                            if (StringUtils.isNotBlank(unitName)) {
                                lineRequest.setInventoryUnit(unitName);
                            }
                            if (StringUtils.isNotBlank(unitCode)) {
                                lineRequest.setInventoryUnitCode(unitCode);
                            }
                        }
                        // 9. 根据单位名称和编码查询销售单位信息和转换关系
                        QuerySaleUnitRequest querySaleUnitRequest = QuerySaleUnitRequest.builder().scItemId(scItemSDO.getScItemId()).build();
                        querySaleUnitRequest.setInventoryUnit(lineRequest.getInventoryUnit());
                        querySaleUnitRequest.setInventoryUnitCode(lineRequest.getInventoryUnitCode());
                        querySaleUnitRequest.setUnitConvert("1");
                        Result<List<SelectCombox>> querySaleUnitList = forecastOrderLineQueryService.querySaleUnitList(querySaleUnitRequest);
                        if (querySaleUnitList.isSuccess() && Objects.nonNull(querySaleUnitList.getResult())) {
                            List<SelectCombox> result = querySaleUnitList.getResult();
                            Map<String, SelectCombox> unitMap = new HashMap<>();
                            Nullable.stream(result).forEach(t -> {
                                unitMap.put(t.getValue(), t);
                            });
                            SelectCombox selected = unitMap.get(detail.getSaleUnit());
                            if (selected != null) {
                                lineRequest.setSaleUnitName(selected.getLabel());
                                lineRequest.setUnitConvert(selected.getExt());
                            }
                            SelectCombox inventoryMap = unitMap.get(lineRequest.getInventoryUnitCode());
                            if (inventoryMap != null) {
                                lineRequest.setInventoryUnit(inventoryMap.getLabel());
                            }
                        }
                    }

                    if (!scItemSDOMap.containsKey(SapAndCrmFieldDealUtils.generateScItemIdField(detail.getScItemId()))) {
                        log.error("MnSapIf015ServiceImpl#externalSyncSaleOrder 货品编码转换失败 scItemId={}", detail.getScItemId());
                        String msg = "货品编码转换失败";
                        mnSapCommDetail.setStatus("E");
                        mnSapCommDetail.setMessage(msg);
                        buildFailResponse(mnSapCommSDO, msg, "", Lists.newArrayList(mnSapCommDetail));
                        response.setData(Lists.newArrayList(mnSapCommSDO));
                        log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error: {}", JSON.toJSONString(response));
                        saveSapRetry(mnSapIf015Request, msg);
                        return response;
                    }

                    lineRequest.setQuantity(SapAndCrmFieldDealUtils.toInteger(detail.getQuantity()));
                    if(StringUtils.isNotEmpty(lineRequest.getUnitConvert())){
                        BigDecimal stockConversionNum = new BigDecimal(lineRequest.getQuantity())
                                .divide(new BigDecimal(lineRequest.getUnitConvert()), 3, RoundingMode.HALF_UP);
                        lineRequest.setStockConversionNum(stockConversionNum.toPlainString());
                    }

                    lineRequest.setSaleUnit(detail.getSaleUnit());
                    lineRequest.setPrice(extracted(detail.getPrice()));
                    lineRequest.setActivityPrice(extracted(detail.getActivityPrice()));
                    lineRequest.setSubTotalAmount(extracted(detail.getSubTotalAmount()));
                    lineRequest.setReturnFlag(detail.getReturnFlag());
                    lineRequest.setCloseCode(detail.getCloseCode());
                    lineRequest.setCloseReason(detail.getCloseReason());
                    lineRequest.setGiftActivityId(detail.getGiftActivityId());
                    lineRequest.setGiftPromotionId(detail.getGiftPromotionId());
                    lineRequest.setGiftFlag(detail.getGiftFlag());
                    lineRequest.setGiftQuantity(detail.getGiftQuantity());
                    lineRequest.setSpecialActivityId(detail.getSpecialActivityId());
                    lineRequest.setSpecialPromotionId(detail.getSpecialPromotionId());
                    lineRequest.setActivityId(detail.getActivityId());
                    lineRequest.setManualPromotionId(detail.getManualPromotionId());
                    lineRequest.setTaxRate(detail.getTaxRate());
                    lineRequest.setTurningPrice(extracted(detail.getTurningPrice()));
                    lineRequest.setDctBeforePrice(extracted(detail.getDctBeforePrice()));
                    lineRequest.setDiscount(StringUtils.isEmpty(detail.getDiscount()) ? null : detail.getDiscount().trim());
                    lineRequest.setNkPrice(extracted(detail.getNkPrice()));
                    lineRequest.setConfirmQuantity(detail.getConfirmQuantity());
                    lineRequest.setShipPoint(detail.getShipPoint());
                    lineRequest.setActOccFee(detail.getExt() != null ? String.valueOf(detail.getExt().multiply(new BigDecimal(100))) : null);
                    lineRequest.setActOccQty(detail.getExt1() != null ? String.valueOf(detail.getExt1().multiply(new BigDecimal(100))) : null);

                    // 10. 根据工厂编码和库存地点编码查询逻辑仓库信息
                    WmsQueryWarehouseZoneListRequest warehouseZoneListRequest = new WmsQueryWarehouseZoneListRequest();
                    warehouseZoneListRequest.setSapFactoryCode(detail.getFactoryCode());
                    warehouseZoneListRequest.setWarehouseCode(detail.getInventoryCode());
                    WmsQueryWarehouseZoneListResponse warehouseZoneList = unifiedInventoryService.wmsQueryWarehouseZoneList(warehouseZoneListRequest);
                    if (order == null || !"300".equals(order.getOrderCategoryCode()) && CollectionUtils.isNotEmpty(warehouseZoneList.getResult())) {
                        WarehouseInfo warehouseInfo = warehouseZoneList.getResult().get(0);
                        lineRequest.setWarehouseCode(warehouseInfo.getId());
                        warehouseCode = warehouseInfo.getCode();
                        if(Objects.isNull(order)){
                            request.setWareHouseOutCode(warehouseInfo.getCode());
                        }
                        lineRequest.setWarehouseName(warehouseInfo.getName());
                    }
//                    lineRequest.setFactoryCode(detail.getFactoryCode());
//                    lineRequest.setInventoryCode(detail.getInventoryCode());
                    //F-B-b场景，SAP明细回传时，不要把SAP返回的“过账仓”覆盖B-b共享仓
                    if (order == null || !"300".equals(order.getOrderCategoryCode())) {
                            lineRequest.setFactoryCode(detail.getFactoryCode());
                            lineRequest.setInventoryCode(detail.getInventoryCode());
                    }

                    //add by 皓晖 at 20211217 for 015接口中增加行明细备注字段 begin
                    lineRequest.setRemark(detail.getExt2());
                    lineRequest.setExt3(detail.getExt3());
                    lineRequest.setExt4(detail.getExt4());
                    lineRequest.setExt5(detail.getExt5());
                    lineRequest.setExt6(detail.getExt6());
                    //todo 增加生产日期

                    //sap 默认时间空值的格式伟"000000"
                    if (StringUtils.isNotBlank(detail.getExt7())&&!detail.getExt7().equals("00000000")){
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
                        Date productionTime = null;
                        try {
                            productionTime = simpleDateFormat.parse(detail.getExt7());
                            lineRequest.setProductionTime(productionTime);
                        } catch (ParseException e) {
                            log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder productionTime parse error: {}", detail.getExt7());
                        }
                    }
                    //add by 皓晖 at 20211217 for 015接口中增加行明细备注字段 end

                    //20220112 活动参数构建
                    StringBuilder activityCode = new StringBuilder();

                    List<ActivitySDO> activitySDOS = new ArrayList<>();
                    if (detail.getGiftPromotionId() != null) {
                        ActivitySDO activitySDO = new ActivitySDO();
                        activitySDO.setActivityTermid(detail.getGiftPromotionId());
                        activitySDO.setActivityCode(detail.getGiftActivityId());
                        activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                        activitySDOS.add(activitySDO);
                        activityCode.append(detail.getGiftActivityId()).append("/");
                    }
                    if (detail.getSpecialPromotionId() != null) {
                        ActivitySDO activitySDO = new ActivitySDO();
                        activitySDO.setActivityTermid(detail.getSpecialPromotionId());
                        activitySDO.setActivityCode(detail.getSpecialActivityId());
                        activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                        activitySDOS.add(activitySDO);
                        activityCode.append(detail.getSpecialActivityId()).append("/");
                    }
                    if (detail.getManualPromotionId() != null) {
                        ActivitySDO activitySDO = new ActivitySDO();
                        activitySDO.setActivityTermid(detail.getManualPromotionId());
                        activitySDO.setActivityCode(detail.getActivityId());
                        activitySDO.setActivityfee(converterActivityPrice(detail.getActivityPrice()));
                        activitySDOS.add(activitySDO);
                        activityCode.append(detail.getSpecialActivityId()).append("/");
                    }
                    if (activityCode.length() > 0) {
                        String s = activityCode.toString();
                        lineRequest.setActivityCode(s.substring(0, s.length() - 1));
                    }

                    lineRequest.setActivityFeature(JSON.toJSONString(activitySDOS));

                    orderLineRequests.add(lineRequest);

                    mnSapCommDetail.setStatus("S");
                    mnSapCommDetail.setMessage("成功");
                    mnSapCommDetails.add(mnSapCommDetail);
                }
                mnSapCommSDO.setItem(mnSapCommDetails);
                request.setModifyOrderLineRequests(orderLineRequests);
                //业务单元只有一盘货
                if(Objects.isNull(order)){
                    setBisUnitCode(data, request, warehouseCode);
                    setOneStockFlag(mnSapIf015Request, request, from013);
                }
                // 11. 查询客户账款
                CreditQueryRequest creditQueryRequest = new CreditQueryRequest();
                creditQueryRequest.setOrganizationCode(request.getSaleOrganizationCode());
                creditQueryRequest.setChannelCode(request.getSapChannel());
                creditQueryRequest.setItemGroupCode(request.getProductGroupCode());
                creditQueryRequest.setCustomerCode(request.getSoldPartCode());
                Result<CreditInfoSDO> balanceResult = creditQueryService.queryCreditBalance(creditQueryRequest);
                log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder balanceResult={}", JSON.toJSONString(balanceResult));
                if (balanceResult.getResult() != null) {
                    request.setCustomerAccounts(balanceResult.getResult().getBalance());
                }
            }
            log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder request={}", JSON.toJSONString(request));

            // 13. 执行创建或修改订单
            com.epoch.app.crb2btradecenter.dto.request.ModifyOrderRequest modifyOrderRequest =
                    JSON.parseObject(JSON.toJSONString(request), com.epoch.app.crb2btradecenter.dto.request.ModifyOrderRequest.class);
            //因为fastjson转换是时间戳 这边需要转成符合接口入参的yyyy-MM-dd HH:mm:ss
            modifyOrderRequest.setExpectedDeliveryTime(TimeUtil.convertYYYYMMdd2YYYYMMddHHmmss(mnSapIf015Request.getData().getExpectedDeliveryTime()));
            // 如果按外部订单号为空，则为更新操作，creator不赋值，防止落库到表中modifier
            if (Objects.nonNull(order) && StringUtils.isBlank(order.getOuterOrderId())) {
                modifyOrderRequest.setCreator(null);
            }
            modifyOrderRequest.setFromSys("APP_SAP");
            Result<Boolean> modifySaleOrder = orderWriteService.modifySaleOrder(modifyOrderRequest);
            if (Objects.isNull(modifySaleOrder)) {
                String msg = "修改销售订单异常";
                buildFailResponse(mnSapCommSDO, msg, "", null);
                response.setData(Lists.newArrayList(mnSapCommSDO));
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder modifySaleOrder error: {}", JSON.toJSONString(response));
                saveSapRetry(mnSapIf015Request, msg);
                return response;
            }
            if (!modifySaleOrder.isSuccess()) {
                buildFailResponse(mnSapCommSDO, modifySaleOrder.getMessage(), "", null);
                response.setData(Lists.newArrayList(mnSapCommSDO));
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder modifySaleOrder error: {}", JSON.toJSONString(response));
                saveSapRetry(mnSapIf015Request, modifySaleOrder.getMessage());
                return response;
            }

            //如果需要校验时间戳 放入时间戳
            if (checkTimestamp) {
                cacheRequestTime(mnSapIf015Request.getData().getOutOrderId(), mnSapIf015Request.getData().getExt1());
            }

            try {
                // 14. 调用017交货单同步接口
                retryConsignmentOrder(data.getOutOrderId());
            } catch (Throwable e) {
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder retryConsignmentOrder error", e);
            }

            try {
                // 15. 重试004先于调拨单的物料凭证
                retryExternalSyncMaterial(data.getOutOrderId());
            } catch (Throwable e) {
                log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder retry error", e);
            }

            // 16. 发送mq消息，异步发送kafka消息通知应用端
            asyncSendMsgToKafka(data, order);

            // 17. 发送MQ消息通知其他中心
            sendMsg(order);
        } catch (Throwable e) {
            log.error("MnSapIf015V2ServiceImpl#externalSyncSaleOrder error", e);
            String msg = "015接口同步数据异常";
            saveSapRetry(mnSapIf015Request, msg);
            List<MnSapCommDetail> mnSapCommDetails = null;
            if (mnSapIf015Request != null && mnSapIf015Request.getData() != null
                    && CollectionUtils.isNotEmpty(mnSapIf015Request.getData().getItems())) {
                mnSapCommDetails = new ArrayList<>();
                for (MnSapIf015Detail item : mnSapIf015Request.getData().getItems()) {
                    MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                    mnSapCommDetail.setItemKey(item.getItem_key());
                    mnSapCommDetail.setStatus("E");
                    mnSapCommDetail.setMessage(msg);
                    mnSapCommDetails.add(mnSapCommDetail);
                }
            }
            buildFailResponse(mnSapCommSDO, msg, "", mnSapCommDetails);
        }
        response.setData(Lists.newArrayList(mnSapCommSDO));
        log.info("MnSapIf015V2ServiceImpl#externalSyncSaleOrder 执行结束");
        return response;
    }

    /**
     * 一盘货订单打标
     * @param mnSapIf015Request
     * @param request
     * @param from013
     */
    private void setOneStockFlag(MnSapIf015Request mnSapIf015Request, ModifyOrderRequest request, boolean from013) {
        try {
            // 从013过来的请求，都是一盘货订单，在013里面已做过判断 一盘货的才转到015
            boolean isOneStock = from013 || isInPilotScope(mnSapIf015Request.getData());
            if(isOneStock){
                // SAP创建的订单，判断如果是一盘货订单，则在features里面打标os=OrderCenter
                JSONObject features = new JSONObject();
                if(StringUtils.isNotBlank(request.getFeatures())){
                    try {
                        features.putAll(JSON.parseObject(request.getFeatures()));
                    } catch (Exception e) {
                        log.error("features is invalid. features=" + request.getFeatures(), e);
                    }
                }
                features.put("os", JsonUtil.ORDER_CENTER_TAG);
                request.setFeatures(features.toJSONString());
                log.info("MnSapIf015V2ServiceImpl isOneStock features={}", request.getFeatures());
            }
        } catch (Exception e) {
            log.error("MnSapIf015V2ServiceImpl#setOneStockFlag error", e);
        }
    }

    /**
     * 根据客户信息判断业务单元
     *  @param data
     * @param request
     * @param warehouseCode
     */
    private void setBisUnitCode(MnSapIf015SDO data, ModifyOrderRequest request, String warehouseCode) {
        String customerGroup = null;
        try {
            QueryCustomerRequest customerRequest = new QueryCustomerRequest();
            customerRequest.setSalesOrganizationCode(data.getSaleOrganizationCode());
            customerRequest.setSalesChannelCode(data.getSapChannel());
            customerRequest.setBusinessTypes(Lists.newArrayList(data.getProductGroupCode()));
            customerRequest.setSoldToPartyCode(data.getSoldPartCode());
            customerRequest.setSize(1);
            log.info("MnSapIf015V2ServiceImpl#queryCustomer request={}", JSON.toJSONString(customerRequest));
            QueryCustomerResponse customerResponse = otsApplicationAdapterSdkService.queryCustomer(customerRequest);
            log.info("MnSapIf015V2ServiceImpl#queryCustomer response={}", JSON.toJSONString(customerResponse));
            if (customerResponse != null && CollectionUtils.isNotEmpty(customerResponse.getItems())) {
                if (customerResponse.getTotal() == 1) {
                    JSONObject json = JSON.parseObject(JSON.toJSONString(customerResponse.getItems().get(0)));
                    customerGroup = json != null ? json.getString("customerGroupCode") : null;
                }
            }
        } catch (Exception e) {
            log.error("MnSapIf015V2ServiceImpl#queryCustomer error", e);
        }
        try {
            if (StringUtils.isNotBlank(customerGroup)) {
                // 根据客户信息获取业务单元
                GetBusinessUnitSalesRequest unitSalesRequest = new GetBusinessUnitSalesRequest();
                unitSalesRequest.setSalesOrganizationCode(data.getSaleOrganizationCode());
                unitSalesRequest.setBusinessChannelCode(data.getSapChannel());
                unitSalesRequest.setSoldToPartyCode(data.getSoldPartCode());
                unitSalesRequest.setCustomerGroup(customerGroup);
                unitSalesRequest.setWarehouseCode(warehouseCode);
                log.info("MnSapIf015V2ServiceImpl#getBusinessUnitSales request={}", JSON.toJSONString(unitSalesRequest));
                Result<String> result = otsApplicationAdapterSdkService.getBusinessUnitSales(unitSalesRequest);
                log.info("MnSapIf015V2ServiceImpl#getBusinessUnitSales result={}", JSON.toJSONString(result));
                if (result != null && StringUtils.isNotBlank(result.getResult())) {
                    request.setBisUnitCode(result.getResult());
                } else {
                    request.setBisUnitCode(data.getSaleOrganizationCode());
                }
            } else {
                log.info("MnSapIf015V2ServiceImpl#getBusinessUnitSales customerGroup is empty.");
                request.setBisUnitCode("6000");
            }
        } catch (Exception e) {
            log.error("MnSapIf015V2ServiceImpl#getBusinessUnitSales error ", e);
            request.setBisUnitCode("6000");
        }
    }

    /**
     * 根据工厂编码 + 库存地点
     * @return
     */
    public boolean isInPilotScope(MnSapIf015SDO data){
        if (CollectionUtils.isEmpty(data.getItems()) || StringUtils.isBlank(data.getItems().get(0).getFactoryCode())) {
            return false;
        }
        CheckPilotByFactoryCodeAndInventoryCodeRequest request = new CheckPilotByFactoryCodeAndInventoryCodeRequest();
        request.setFactoryCode(data.getItems().get(0).getFactoryCode());
        request.setInventoryCode(data.getItems().get(0).getInventoryCode());
        log.info("MnSapIf015V2ServiceImpl#isInPilotScope request={}", JSON.toJSONString(request));
        Result<Boolean> result = otsApplicationAdapterSdkService.checkPilotByFactoryCodeAndInventoryCode(request);
        log.info("MnSapIf015V2ServiceImpl#isInPilotScope result={}", JSON.toJSONString(result));
        return Optional.ofNullable(result).map(Result::getResult).orElse(Boolean.FALSE);
    }

    /**
     * 发送mq消息通知其他中心
     */
    private void sendMsg(Order order) {
        log.info("MnSapIf015V2ServiceImpl#sendMsg order={}", order);
        if (Objects.isNull(order) || Objects.isNull(order.getId())) {
            return;
        }
        QuerySingleRequest querySingleRequest = new QuerySingleRequest();
        querySingleRequest.setMainOrderId(order.getId().toString());
        OrderSDO orderSDO = orderQueryService.querySingle(querySingleRequest);
        log.info("MnSapIf015V2ServiceImpl#sendMsg querySingle={}", orderSDO);
        if (Objects.isNull(orderSDO)) {
            return;
        }
        if (!JsonUtil.checkOrderCenterTag(orderSDO.getFeatures())) {
            // 非订单中心订单不发消息
            return;
        }

        CommonAsyncMessageResponse commonAsyncMessageResponse = new CommonAsyncMessageResponse();
        commonAsyncMessageResponse.setEventCode("SalesOrder_updated_sap");
        commonAsyncMessageResponse.setEventName("销售订单更新");
        commonAsyncMessageResponse.setData(Lists.newArrayList(orderSDO));

        log.info("MnSapIf015V2ServiceImpl#sendMsg commonAsyncMessageResponse={}", commonAsyncMessageResponse);
        messageService.sendMessage("ORDER_STATUSCHANGE_PUSH_MESSAGE", "CR_SALEORDER_V2", "SalesOrderEvent",
                JSONObject.toJSONString(commonAsyncMessageResponse));
    }

    /**
     * 发送mq消息，异步发送kafka消息通知应用端
     */
    private void asyncSendMsgToKafka(MnSapIf015SDO data, Order order) {
        if (StringUtils.isBlank(data.getOutOrderId()) || Objects.isNull(order)) {
            return;
        }
        if (!JsonUtil.checkOrderCenterTag(order.getFeatures())) {
            // 非订单中心订单不发kafka消息
            return;
        }

        PushOrderInfoToMnSideRequestOrderInfo pushOrderInfo = new PushOrderInfoToMnSideRequestOrderInfo();
        pushOrderInfo.setSalesOrderNo(order.getOrderBizId());
        pushOrderInfo.setOrderStatus(SalesOrderPushStatusEnum.SUCCESS_UPDATE.getOrderStatusCode());

        CommonAsyncMessageResponse commonAsyncMessageResponse = new CommonAsyncMessageResponse();
        commonAsyncMessageResponse.setEventCode(AsyncMessageEventEnum.SALES_ORDER_UPDATE.getValue());
        commonAsyncMessageResponse.setEventName(AsyncMessageEventEnum.SALES_ORDER_UPDATE.getLabel());
        commonAsyncMessageResponse.setEventTime(String.valueOf(new Date().getTime()));
        commonAsyncMessageResponse.setFromSys(order.getFromSys());
        commonAsyncMessageResponse.setBusinessUnitCode(order.getBisUnitOutCode());
        commonAsyncMessageResponse.setData(Arrays.asList(pushOrderInfo));
        messageService.sendMessage("ORDER_STATUSCHANGE_PUSH_MESSAGE", "CR_SALEORDER_V2", "SaleOrderPushMn",
                JSONObject.toJSONString(commonAsyncMessageResponse));
        log.info("MnSapIf015V2Service#asynSendMsgToKafka commonAsyncMessageResponse: {}", commonAsyncMessageResponse);
    }

    private static String extracted(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        BigDecimal val = new BigDecimal(s.trim());
        val = val.multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN);
        return val.toString();
    }

    private static Long converterActivityPrice(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        BigDecimal val = new BigDecimal(s);
        return val.multiply(new BigDecimal(100)).longValue();
    }

    /**
     * 保存sap重试记录
     */
    public void saveSapRetry(MnSapIf015Request request, String message) {
        try {
            if (request == null) {
                return;
            }
            SapRetrySaveRequest sapRetrySaveRequest = SapRetrySaveRequest.builder()
                    .param(JSON.toJSONString(request))
                    .msg(message)
                    .messageId(request.getMessageHeader().getMessageId())
                    .apiCode(SapApiCode.SAP015.getValue())
                    .outKey(request.getData().getOutOrderId())
                    .status(RetryStatus.FAIL.getValue())
                    .requestTime(request.getData().getExt1())
                    .build();
            sapRetryWriteService.save(sapRetrySaveRequest);
        } catch (Throwable e) {
            log.error("sapRetrySaveError", e);
        }
    }

    private boolean checkModifierTime(MnSapIf015SDO data, MnSapCommSDO mnSapCommSDO, MnSapIf015Request mnSapIf015Request) {
        boolean checkStatus = true;
        String modifierTime = epochCacheService.get(BcOtsConstants.REDIS_CACHE_CODE(), SALES_ORDER_CACHE_KEY + data.getOutOrderId());
        if (StringUtils.isNotBlank(modifierTime)) {
            String[] modifierTimeArray = modifierTime.split("\\.");
            String[] extArray = data.getExt1().split("\\.");
            if (Long.parseLong(modifierTimeArray[0]) > Long.parseLong(extArray[0])) {
                checkStatus = false;
            } else if (Long.valueOf(modifierTimeArray[0]).longValue() == Long.valueOf(extArray[0]).longValue()) {
                if (Long.parseLong(modifierTimeArray[1]) >= Integer.valueOf(extArray[1]).longValue()) {
                    checkStatus = false;
                }
            }
        }

        if (!checkStatus) {
            // 失败放入重试表
            String msg = "当前修改时间早于上一次，不允许更新";
            saveSapRetry(mnSapIf015Request, msg);
            List<MnSapCommDetail> mnSapCommDetails = null;
            if (CollectionUtils.isNotEmpty(data.getItems())) {
                mnSapCommDetails = new ArrayList<>();
                for (MnSapIf015Detail item : data.getItems()) {
                    MnSapCommDetail mnSapCommDetail = new MnSapCommDetail();
                    mnSapCommDetail.setItemKey(item.getItem_key());
                    mnSapCommDetail.setStatus("E");
                    mnSapCommDetail.setMessage(msg);
                    mnSapCommDetails.add(mnSapCommDetail);
                }
            }
            buildFailResponse(mnSapCommSDO, msg, "49", mnSapCommDetails);
        }

        return checkStatus;
    }

    /**
     * 缓存请求时间，由于PI转发消息无序，防止老的请求把新的请求数据覆盖掉
     */
    private void cacheRequestTime(String key, String time) {
        if (StringUtils.isAnyBlank(key, time)) {
            return;
        }
        epochCacheService.put(BcOtsConstants.REDIS_CACHE_CODE(),
                SALES_ORDER_CACHE_KEY + key,time,
                SAP_TIMESTAMP_CACHE_EXPIRE,
                TimeUnit.SECONDS);
    }

    /**
     * 重试017交货单接口
     */
    private void retryConsignmentOrder(String outOrderId) {
        if (StringUtils.isBlank(outOrderId)) {
            return;
        }
        SapRetryLoadListRequest sapRetryLoadListRequest = new SapRetryLoadListRequest();
        sapRetryLoadListRequest.setExt(outOrderId);
        sapRetryLoadListRequest.setStatus(RetryStatus.FAIL.getValue());
        sapRetryLoadListRequest.setLimit(MAX_PAGE_SIZE);
        sapRetryLoadListRequest.setApiCode("MnSapIf017$externalSyncDeliveryOrder");
        sapRetryLoadListRequest.setDir("request_time");
        sapRetryLoadListRequest.setAsc(Boolean.TRUE);
        Result<List<SapRetry>> listResult = sapRetryService.loadList(sapRetryLoadListRequest);
        if (listResult == null || CollectionUtils.isEmpty(listResult.getResult())) {
            return;
        }
        for (SapRetry sapRetry : listResult.getResult()) {
            try {
                if (sapRetry.getRetryTimes() > 80) {
                    continue;
                }
                MnSapIf017Request mnSapIf017Request = JSON.parseObject(sapRetry.getParam(), MnSapIf017Request.class);
                MnSapCommResponse response = mnSapIf017V2Service.externalSyncDeliveryOrder(mnSapIf017Request);
                SapRetryRetryResponse sapRetryRetryResponse = convertSapRetryRetryResponse(response);
                sapRetry.setRetryTimes(sapRetry.getRetryTimes() + 1);
                if (Objects.equals(Boolean.TRUE, sapRetryRetryResponse.getSuccess())) {
                    sapRetry.setStatus(RetryStatus.SUCCESS.getValue());
                } else {
                    LoadRequest loadRequest = new LoadRequest();
                    loadRequest.setId(sapRetry.getId());
                    SapRetry load = sapRetryService.load(loadRequest);
                    if (load == null || RetryStatus.SUCCESS.getValue().equals(load.getStatus())) {
                        log.info("MnSapIf015V2ServiceImpl_retry_isSucceed:{}", JSON.toJSONString(load));
                        continue;
                    }
                    sapRetry.setStatus(RetryStatus.FAIL.getValue());
                    if (StringUtils.isNotBlank(sapRetryRetryResponse.getMsg())) {
                        sapRetry.setMsg(sapRetryRetryResponse.getMsg());
                    }
                }
                sapRetryService.update(sapRetry);
            } catch (Throwable e) {
                log.error("sapBathRetry_error:{}", JSON.toJSONString(sapRetry));
                log.error("sapBathRetry_error", e);
                continue;
            }
        }
    }

    private SapRetryRetryResponse convertSapRetryRetryResponse(MnSapCommResponse mnSapCommResponse) {
        SapRetryRetryResponse response = new SapRetryRetryResponse();
        response.setSuccess(false);
        if (Objects.nonNull(mnSapCommResponse) && CollectionUtils.isNotEmpty(mnSapCommResponse.getData())
                && Objects.nonNull(mnSapCommResponse.getData().get(0).getStatus())) {
            if (mnSapCommResponse.getData().get(0).getStatus().equalsIgnoreCase("S")) {
                response.setSuccess(true);
            } else {
                String message = mnSapCommResponse.getData().get(0).getMessage();
                if (StringUtils.isNotBlank(message)) {
                    response.setMsg(message);
                }
            }
        }
        return response;
    }

    /**
     * 重试004先于调拨单的物料凭证
     */
    private void retryExternalSyncMaterial(String outAllocateOrderId) {
        MaterialSyncRetryLoadListRequest materialSyncRetryLoadListRequest = new MaterialSyncRetryLoadListRequest();
        materialSyncRetryLoadListRequest.setOutOrderId(outAllocateOrderId);
        materialSyncRetryLoadListRequest.setStatus(0);
        materialSyncRetryLoadListRequest.setLimit(MAX_PAGE_SIZE);
        log.info("MnSapIf015V2ServiceImpl#retryExternalSyncMaterial loadList request={}", JSON.toJSONString(materialSyncRetryLoadListRequest));
        Result<List<MaterialSyncRetry>> listResult = materialSyncRetryService.loadList(materialSyncRetryLoadListRequest);
        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
            return;
        }
        for (MaterialSyncRetry materialSyncRetry : listResult.getResult()) {
            try {
                MnSapIf004Request mnSapIf004Request = JSON.parseObject(materialSyncRetry.getRequestParams(), MnSapIf004Request.class);
                log.info("MnSapIf015V2ServiceImpl#retryExternalSyncMaterial externalSyncMaterial request={}", JSON.toJSONString(mnSapIf004Request));
                MnSapCommResponse response = mnSapIf004V2Service.externalSyncMaterial(mnSapIf004Request);
                log.info("MnSapIf015V2ServiceImpl#retryExternalSyncMaterial externalSyncMaterial response={}", JSON.toJSONString(response));
            } catch (Throwable e) {
                log.error("MnSapIf015V2ServiceImpl#retryExternalSyncMaterial externalSyncMaterial error", e);
            }
        }
    }

    /**
     * 货品转换
     */
    private Result<List<ScItemSDO>> convertSapRetryRetryResponse(Object data) {
        ScItemFromDBResponse response = JSON.parseObject(JSON.toJSONString(data), ScItemFromDBResponse.class);
        List<ScItemSDO> scItemSDOS = Optional.ofNullable(response)
                .map(ScItemFromDBResponse::getResult)
                .map(ScItemResult::getResult)
                .map(ScItemSearchResult::getSearchResult)
                .orElse(null);
        if (CollectionUtils.isEmpty(scItemSDOS)) {
            return null;
        }
        return Result.listSuccess(scItemSDOS, scItemSDOS.size());
    }

    /**
     * 从DB查询客户地址数据
     */
    private CustomerAddressSDO pageQueryCustomerAddress(String addressCode,
                                          String customerCode,
                                          String orgSaleOrganizationCode,
                                          String channelCode,
                                          String itemGroup) {
        CustomerAddressLoadListRequest loadListRequest = new CustomerAddressLoadListRequest();
        loadListRequest.setAddressCode(addressCode);
        loadListRequest.setCustomerCode(customerCode);
        loadListRequest.setOrgSaleOrganizationCode(orgSaleOrganizationCode);
        loadListRequest.setChannelCode(channelCode);
        loadListRequest.setItemGroup(itemGroup);
        Result<List<CustomerAddress>> listResult = customerAddressService.loadCustomerAddressList(loadListRequest);
        if (Objects.isNull(listResult) || CollectionUtils.isEmpty(listResult.getResult())) {
            return null;
        }
        CustomerAddress customerAddress = listResult.getResult().get(0);

        CustomerAddressSDO customerAddressSDO = new CustomerAddressSDO();
        customerAddressSDO.setPrincipal(customerAddress.getPrincipal());
        customerAddressSDO.setCustomerCode(customerAddress.getCustomerCode());
        if (StringUtils.isNotBlank(customerAddress.getCustomerCode())) {
            CustomerLoadListRequest customerLoadListRequest = new CustomerLoadListRequest();
            customerLoadListRequest.setCode(customerAddress.getCustomerCode());
            Result<List<Customer>> customerList = customerService.loadCustomerList(customerLoadListRequest);
            if (customerList != null && CollectionUtils.isNotEmpty(customerList.getResult())) {
                customerAddressSDO.setCustomerName(customerList.getResult().get(0).getName());
            }
        }
        customerAddressSDO.setAddressCode(customerAddress.getAddressCode());
        customerAddressSDO.setAddressName(customerAddress.getAddressName());
        customerAddressSDO.setContactName(customerAddress.getContactName());
        customerAddressSDO.setCellphoneNumber(customerAddress.getCellphoneNumber());
        customerAddressSDO.setOrgSaleDepartmentCode(customerAddress.getOrgSaleDepartmentCode());
        customerAddressSDO.setOrgSaleChannelCode(customerAddress.getOrgSaleChannelCode());
        customerAddressSDO.setOrgBussinessUnitCode(customerAddress.getOrgBussinessUnitCode());
        return customerAddressSDO;
    }

    /**
     * 构造失败结果
     */
    private void buildFailResponse(MnSapCommSDO mnSapCommSDO, String errMsg, String errCode, List<MnSapCommDetail> items) {
        mnSapCommSDO.setStatus("E");
        mnSapCommSDO.setMessage(errMsg);
        mnSapCommSDO.setErrCode(Optional.ofNullable(errCode).orElse("999"));
        mnSapCommSDO.setItem(items);
    }

    //************************************业中订单调用逻辑************************************
    /**
     * 根据销售组织判断是否需要走业中接口查数据
     */
    private boolean checkSaleOrganizationCode(String saleOrganizationCode) {
        String saleOrganizations = OtsApplicationAdapterSdkConstants.BC_SALES_ORG_LIST();
        log.info("checkSaleOrganizationCode saleOrganizations={}",saleOrganizations);
        if (StringUtils.isEmpty(saleOrganizations)) {
            return false;
        }

        List<String> salesOrgList = Arrays.stream(saleOrganizations.split(","))
                .filter(code -> code.equals(saleOrganizationCode))
                .collect(Collectors.toList());
        return CollectionUtils.isNotEmpty(salesOrgList);
    }

    /**
     * 通过客户中心接口查询售达方和送达方信息
     */
    private CustomerAddressSDO queryShipToPartyAndSoldToParty(MnSapIf015SDO data) {
        try {
            // 查询售达方信息
            SoldToPartyQueryAccurateRequest soldRequest = new SoldToPartyQueryAccurateRequest();
            Map<String, String> soldMap = new HashMap<>();
            soldMap.put("businessType", data.getProductGroupCode());
//            shipMap.put("businessUnitCode", data.getcode());
            soldMap.put("salesChannelCode", data.getSapChannel());
            soldMap.put("salesOrganizationCode", data.getSaleOrganizationCode());
            soldMap.put("soldToPartyCode", data.getSoldPartCode());
            soldRequest.setSoldToPartyAccurateQueryReq(Lists.newArrayList(soldMap));
            log.info("MnSapIf015V2ServiceImpl#queryShipToPartyAndSoldToParty soldRequest={}", JSON.toJSONString(soldRequest));
            Result<List<SoldToPartyInternalResp>> listSoldResult = bcService.soldToPartyQueryAccurate(soldRequest);
            log.info("MnSapIf015V2ServiceImpl#queryShipToPartyAndSoldToParty listSoldResult={}", JSON.toJSONString(listSoldResult));
            if (Objects.isNull(listSoldResult) || CollectionUtils.isEmpty(listSoldResult.getResult())) {
                return null;
            }
            SoldToPartyInternalResp soldToParty = listSoldResult.getResult().get(0);

            ShipToPartyQueryAccurateRequest shipRequest = new ShipToPartyQueryAccurateRequest();
            Map<String, String> shipMap = new HashMap<>();
            shipMap.put("businessType", data.getProductGroupCode());
            shipMap.put("salesChannelCode", data.getSapChannel());
            shipMap.put("salesOrganizationCode", data.getSaleOrganizationCode());
            shipMap.put("soldToPartyCode", data.getSoldPartCode().replaceAll("^0+",""));
            shipMap.put("shipToPartyCode", data.getDeliveryPartCode().replaceAll("^0+",""));
            shipRequest.setShipToPartyAccurateQueryReq(Lists.newArrayList(shipMap));
            log.info("MnSapIf015V2ServiceImpl#queryShipToPartyAndSoldToParty shipRequest={}", JSON.toJSONString(shipRequest));
            Result<List<ShipToPartyInternalResp>> listShipResult = bcService.shipToPartyQueryAccurate(shipRequest);
            log.info("MnSapIf015V2ServiceImpl#queryShipToPartyAndSoldToParty listShipResult={}", JSON.toJSONString(listShipResult));
            if (Objects.isNull(listShipResult) || CollectionUtils.isEmpty(listShipResult.getResult())) {
                return null;
            }
            ShipToPartyInternalResp shipToParty = listShipResult.getResult().get(0);

            CustomerAddressSDO customerAddressSDO = new CustomerAddressSDO();
            customerAddressSDO.setCustomerCode(soldToParty.getSoldToPartyCode());
            customerAddressSDO.setCustomerName(soldToParty.getSoldToPartyName());
            customerAddressSDO.setAddressCode(shipToParty.getShipToPartyCode());
            customerAddressSDO.setAddressName(shipToParty.getShipToPartyName());
            customerAddressSDO.setContactName(shipToParty.getConsigneeName());
            customerAddressSDO.setCellphoneNumber(shipToParty.getConsigneePhone());
            customerAddressSDO.setOrgSaleDepartmentCode(soldToParty.getOuterSalesGroupCode());
            // 业中订单不更新渠道信息，防止和创建信息不一致
//            customerAddressSDO.setOrgSalesDepartmentName(soldToParty.getOuterSalesGroup());
//            customerAddressSDO.setOrgSaleChannelCode(soldToParty.getSalesChannelCode());
            customerAddressSDO.setOrgBussinessUnitCode(soldToParty.getBusinessUnitCode());
            return customerAddressSDO;
        } catch (Exception e) {
            log.error("MnSapIf015V2ServiceImpl#queryShipToPartyAndSoldToParty error", e);
        }
        return null;
    }

    /**
     * 通过客户中心接口查询组织信息
     */
    private List<ActualSalesOrgListResp> salesOrgPage(MnSapIf015SDO data) {
        try {
            SalesOrgPageRequest request = new SalesOrgPageRequest();
            request.setDivision(data.getProductGroupCode());
            request.setOrgCode(data.getSaleOrganizationCode());
            log.info("MnSapIf015V2ServiceImpl#salesOrgPage request={}", JSON.toJSONString(request));
            Result<List<ActualSalesOrgListResp>> result = bcService.salesOrgPage(request);
            log.info("MnSapIf015V2ServiceImpl#salesOrgPage result={}", JSON.toJSONString(result));
            if (Objects.isNull(result) || CollectionUtils.isEmpty(result.getResult())) {
                return Lists.newArrayList();
            }
            return result.getResult();
        } catch (Exception e) {
            log.error("MnSapIf015V2ServiceImpl#salesOrgPage error", e);
        }
        return Lists.newArrayList();
    }
}
